﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Common.Utilities;
using DiscoveryLogic.Common.Utilities.TextMatch;

namespace DiscoveryLogic.Analytics.DataObjects.Networks
{
    [Serializable]
    public class Network
    {
        #region props
        private string _NetworkName;
        /// <summary></summary>
        public string NetworkName
        {
            get
            {
                return this._NetworkName;
            }
            set
            {
                this._NetworkName = value;
            }
        }

        private string _Author;
        /// <summary></summary>
        public string Author
        {
            get
            {
                return this._Author;
            }
            set
            {
                this._Author = value;
            }
        }

        private DateTime _CreatedOn;
        /// <summary></summary>
        public DateTime CreatedOn
        {
            get
            {
                return this._CreatedOn;
            }
            set
            {
                this._CreatedOn = value;
            }
        }

        private DateTime _UpdatedOn;
        /// <summary></summary>
        public DateTime UpdatedOn
        {
            get
            {
                return this._UpdatedOn;
            }
            set
            {
                this._UpdatedOn = value;
            }
        }

        private List<EntityBase> _Records;
        /// <summary></summary>
        public List<EntityBase> Records
        {
            get
            {
                return this._Records;
            }
            set
            {
                this._Records = value;
            }
        }

        private List<Link> _Links;
        /// <summary></summary>
        public List<Link> Links
        {
            get
            {
                return this._Links;
            }
            set
            {
                this._Links = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        /// <param name="networkName"></param>
        /// <param name="entityType"></param>
        /// <param name="fieldMappings">prop name -> column name</param>
        /// <param name="idField"></param>
        /// <param name="nameField"></param>
        /// <param name="provider"></param>
        public Network(string networkName, 
            EntityType entityType, 
            Dictionary<string,string> fieldMappings,
            string idField, string nameField,
            SetDataProvider provider)
        {
            this._NetworkName = networkName;
            this._Author = Environment.UserName;
            this._CreatedOn = DateTime.Now;
            this._UpdatedOn = DateTime.Now;
            this._Records=new List<EntityBase>();
            this._Links=new List<Link>();

            DataTable dt = provider.GetDataFromProvider();
            Type objType = EntityTypeUtil.GetType(entityType);
            if(dt !=null && dt.Rows.Count>0)
            {
                PropertyInfo[] props = EntityTypeUtil.GetProperties(entityType);
                foreach (DataRow dr in dt.Rows)
                {
                    EntityBase entity =(EntityBase) Activator.CreateInstance(
                        objType, idField, nameField);
                    foreach (PropertyInfo prop in props)
                    {
                        if(fieldMappings.ContainsKey(prop.Name))
                        {
                            string colName = fieldMappings[prop.Name];
                            if(dr[colName]!=null && dr[colName] !=DBNull.Value)
                            {
                                object fieldValue = dr[colName];
                                SimpleDataType dbType = SimpleDataTypeUtil.ToSimpleDataType(prop.PropertyType);
                                fieldValue = SimpleDataTypeUtil.ReadDbValue(dbType, fieldValue);
                                prop.SetValue(entity, fieldValue, null);
                            }
                        }
                    }
                    this._Records.Add(entity);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="networkName"></param>
        /// <param name="entities"></param>
        /// <param name="links"></param>
        public Network(string networkName, 
            List<EntityBase> entities, 
            List<Link> links)
        {
            this._NetworkName = networkName;
            this._Author = Environment.UserName;
            this._CreatedOn = DateTime.Now;
            this._UpdatedOn = DateTime.Now;
            this._Records = entities;
            this._Links = links;
        }

        public Network(string networkName,
            EntityDataSet entityDataSet)
        {
            this._NetworkName = networkName;
            this._Author = Environment.UserName;
            this._CreatedOn = DateTime.Now;
            this._UpdatedOn = DateTime.Now;
            this._Records = entityDataSet.Entities;
            this._Links = new List<Link>();
        }
        #endregion

        #region read/write
        public void Save()
        {
            XmlDocument xDoc = new XmlDocument();
            string filePath = XmlDataManager.GetFilePath(this._NetworkName, ".net");
            xDoc.LoadXml("<Network></Network>");

            XmlNode root = xDoc.DocumentElement;
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "NetworkName", this.NetworkName);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "Author", this.Author);
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "CreatedOn", this.CreatedOn.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, root, "UpdatedOn", this.UpdatedOn.ToString());

            XmlNode grantRootNode = null;
            XmlNode orgRootNode = null;
            XmlNode pubRootNode = null;
            XmlNode personRootNode = null;
            XmlNode docRootNode = null;
            XmlNode subjRootNode = null;
            XmlNode custRootNode = null;
            if(this.Records !=null && this.Records.Count>0)
            {
                foreach(EntityBase entity in this.Records)
                {
                    XmlNode entityNode = null;
                    if(entity.EntityType==EntityType.Grants)
                    {
                        if(grantRootNode==null)
                        {
                            grantRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Grants");
                            XmlDataUtil.UpdateAttribute(ref xDoc, grantRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, grantRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, grantRootNode, "Grant");
                    }
                    else if (entity.EntityType == EntityType.Organizations)
                    {
                        if (orgRootNode == null)
                        {
                            orgRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Orgs");
                            XmlDataUtil.UpdateAttribute(ref xDoc, orgRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, orgRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, orgRootNode, "Org");
                    }
                    else if (entity.EntityType == EntityType.Persons)
                    {
                        if (personRootNode == null)
                        {
                            personRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Persons");
                            XmlDataUtil.UpdateAttribute(ref xDoc, personRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, personRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, personRootNode, "Person");
                    }
                    else if (entity.EntityType == EntityType.Publications)
                    {
                        if (pubRootNode == null)
                        {
                            pubRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Pubs");
                            XmlDataUtil.UpdateAttribute(ref xDoc, pubRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, pubRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, pubRootNode, "Pub");
                    }
                    else if(entity.EntityType==EntityType.Document)
                    {
                        if(docRootNode==null)
                        {
                            docRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Docs");
                            XmlDataUtil.UpdateAttribute(ref xDoc, docRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, docRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, docRootNode, "Doc");
                    }
                    else if(entity.EntityType==EntityType.Subject)
                    {
                        if(subjRootNode==null)
                        {
                            subjRootNode = XmlDataUtil.AddElement(ref xDoc, root, "Subjs");
                            XmlDataUtil.UpdateAttribute(ref xDoc, subjRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, subjRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, subjRootNode, "Subj");
                    }
                    else if(entity.EntityType==EntityType.Misc)
                    {
                        if(custRootNode==null)
                        {
                            custRootNode = XmlDataUtil.AddElement(ref xDoc, root, "CustomEntities");
                            XmlDataUtil.UpdateAttribute(ref xDoc, custRootNode, "IDField", entity.IDField);
                            XmlDataUtil.UpdateAttribute(ref xDoc, custRootNode, "NameField", entity.NameField);
                        }
                        entityNode = XmlDataUtil.AddElement(ref xDoc, custRootNode, "CustomEntity");
                    }

                    entity.Save(ref xDoc, entityNode);
                }
            }

            if(this.Links !=null && this.Links.Count>0)
            {
                XmlNode linkNodes = XmlDataUtil.AddElement(ref xDoc, root, "Links");
                foreach(Link link in this.Links)
                {
                    XmlNode linkNode = XmlDataUtil.AddElement(ref xDoc, linkNodes, "Link");
                    link.Save(ref xDoc, linkNode);
                }
            }

            xDoc.Save(filePath);
        }

        public static Network Read(string networkName)
        {
            Network network=new Network(networkName, 
                new List<EntityBase>(), new List<Link>());
            XmlDocument xDoc = new XmlDocument();
            string filePath = XmlDataManager.GetFilePath(networkName, ".net");
            xDoc.Load(filePath);
            XmlNode root = xDoc.DocumentElement;
            network.NetworkName = XmlDataUtil.GetAttributeValue(root, "NetworkName", networkName);
            network.Author = XmlDataUtil.GetAttributeValue(root, "Author", Environment.UserName);
            network.CreatedOn = DateTime.Parse(
                XmlDataUtil.GetAttributeValue(
                    root, "CreatedOn", DateTime.Now.ToString()));
            network.UpdatedOn = DateTime.Parse(
                XmlDataUtil.GetAttributeValue(root, "UpdatedOn", DateTime.Now.ToString()));

            XmlNodeList grantNodes = root.SelectNodes("Grants/Grant");
            if (grantNodes != null && grantNodes.Count > 0)
            {
                foreach(XmlNode grantNode in grantNodes)
                {
                    network.Records.Add(GrantDO.Read(grantNode));
                }
            }
            XmlNodeList personNodes = root.SelectNodes("Persons/Person");
            if (personNodes != null && personNodes.Count > 0)
            {
                foreach (XmlNode personNode in personNodes)
                {
                    network.Records.Add(PersonDO.Read(personNode));
                }
            }
            XmlNodeList orgNodes = root.SelectNodes("Orgs/Org");
            if (orgNodes != null && orgNodes.Count > 0)
            {
                foreach (XmlNode orgNode in orgNodes)
                {
                    network.Records.Add(ExternalOrgDO.Read(orgNode));
                }
            }
            XmlNodeList pubNodes = root.SelectNodes("Pubs/Pub");
            if (pubNodes != null && pubNodes.Count > 0)
            {
                foreach (XmlNode pubNode in pubNodes)
                {
                    network.Records.Add(PublicationDO.Read(pubNode));
                }
            }
            XmlNodeList docNodes = root.SelectNodes("Docs/Doc");
            if(docNodes !=null && docNodes.Count>0)
            {
                foreach(XmlNode docNode in docNodes)
                {
                    network.Records.Add(Document.Read(docNode));
                }
            }
            XmlNodeList subjNodes = root.SelectNodes("Subjs/Subj");
            if(subjNodes !=null && subjNodes.Count>0)
            {
                foreach(XmlNode subjNode in subjNodes)
                {
                    network.Records.Add(Subject.Read(subjNode));
                }
            }
            XmlNodeList custEntityNodes = root.SelectNodes("CustomEntities/CustomEntity");
            if(custEntityNodes !=null && custEntityNodes.Count>0)
            {
                foreach(XmlNode custEntityNode in custEntityNodes)
                {
                    network.Records.Add(MiscEntity.Read(custEntityNode));
                }
            }

            XmlNodeList linkNodes = root.SelectNodes("Links/Link");
            if(linkNodes !=null && linkNodes.Count>0)
            {
                foreach(XmlNode linkNode in linkNodes)
                {
                    Link link= Link.Read(linkNode);
                    network.Links.Add(link);
                }
            }
            
            return network;
        }
        #endregion

        #region compose/decompose links
        public void HideVertices(EntityType entityType)
        {
            Type type = null;
            switch(entityType)
            {
                case EntityType.Grants:
                    type = typeof (GrantDO);
                    break;
                case EntityType.Organizations:
                    type = typeof (ExternalOrgDO);
                    break;
                case EntityType.Persons:
                    type = typeof (PersonDO);
                    break;
                case EntityType.Publications:
                    type = typeof (PublicationDO);
                    break;
            }
            
            while (true)
            {
                List<Link> linksToRemove=new List<Link>();
                List<Link> linksToAdd = new List<Link>();
                foreach (Link link1 in this._Links)
                {
                    if (link1.FromType == type || link1.ToType==type)
                    {
                        EntityBase entityToRemove = null;
                        if (link1.FromType == type)
                            entityToRemove = this.Select(entityType, link1.FromKey);
                        else
                            entityToRemove = this.Select(entityType, link1.ToKey);

                        List<EntityBase> toEntities = new List<EntityBase>();
                        foreach(Link link2 in this._Links)
                        {
                            if(link2.FromType==entityToRemove.GetType() && 
                                link2.FromKey==entityToRemove.PKValue())
                            {
                                EntityBase toEntity = this.Select(
                                    this.GetEntityType(link2.ToType), link2.ToKey);
                                if(toEntity==null)
                                    continue;
                                toEntities.Add(toEntity);
                                linksToRemove.Add(link2);
                            }
                        }
                        List<EntityBase> fromEntities=new List<EntityBase>();
                        foreach(Link link3 in this._Links)
                        {
                            if (link3.ToType == entityToRemove.GetType() && 
                                link3.ToKey == entityToRemove.PKValue())
                            {
                                EntityBase fromEntity = this.Select(
                                    this.GetEntityType(link3.FromType),
                                    link3.FromKey);
                                if(fromEntity==null)
                                    continue;
                                fromEntities.Add(fromEntity);
                                linksToRemove.Add(link3);
                                
                            }
                        }

                        if(fromEntities.Count>0 && toEntities.Count>0)
                        {
                            foreach(EntityBase fromEntity in fromEntities)
                            {
                                foreach(EntityBase toEntity in toEntities)
                                {
                                    List<Link> hiddenLinks=new List<Link>();
                                    bool directional = true;
                                    double distance = 0;
                                    foreach(Link hiddenLink in linksToRemove)
                                    {
                                        if(hiddenLink.FromType==fromEntity.GetType() && hiddenLink.FromKey==fromEntity.PKValue())
                                        {
                                            hiddenLinks.Add(hiddenLink);
                                            distance += hiddenLink.Distance;
                                            if(!hiddenLink.Directional)
                                                directional = false;
                                        }
                                        else if(hiddenLink.ToType==toEntity.GetType() && hiddenLink.ToKey==toEntity.PKValue())
                                        {
                                            hiddenLinks.Add(hiddenLink);
                                            distance += hiddenLink.Distance;
                                            if (!hiddenLink.Directional)
                                                directional = false;
                                        }
                                    }

                                    Link newLink = new Link(
                                        fromEntity.GetType(), toEntity.GetType(),
                                        fromEntity.PKValue(), toEntity.PKValue(), 
                                        distance,1, LinkType.CompositeLink,
                                        directional);
                                    newLink.HiddenLinks = hiddenLinks;
                                    linksToAdd.Add(newLink);
                                }
                            }
                            break;
                        }
                    }
                }

                if(linksToRemove.Count==0 || linksToAdd.Count==0)
                    break;
                else
                {
                    foreach (Link link in linksToRemove)
                        this._Links.Remove(link);
                    foreach(Link link in linksToAdd)
                        this._Links.Add(link);
                }
            }
        }

        public void ShowAllHiddenVertices()
        {
            while(true)
            {
                List<Link> compositeLinks=new List<Link>();
                foreach(Link link in this._Links)
                {
                    if(link.RelationType==LinkType.CompositeLink && 
                        link.HiddenLinks !=null && link.HiddenLinks.Count>0)
                    {
                        compositeLinks.Add(link);
                    }
                }
                if (compositeLinks.Count == 0)
                    break;
                else
                {
                    foreach(Link link in compositeLinks)
                    {
                        this._Links.Remove(link);
                        foreach(Link hiddenLink in link.HiddenLinks)
                        {
                            if(!this._Links.Contains(hiddenLink))
                                this._Links.Add(hiddenLink);
                        }
                    }
                }
            }
        }

        private EntityType GetEntityType(Type type)
        {
            if(type==typeof(GrantDO))
                return EntityType.Grants;
            else if(type==typeof(ExternalOrgDO))
                return EntityType.Organizations;
            else if(type==typeof(PersonDO))
                return EntityType.Persons;
            else if(type==typeof(PublicationDO))
                return EntityType.Publications;
            return EntityType.Grants;
        }

        public EntityBase Select(EntityType entityType, string key)
        {
            foreach(EntityBase entity in this._Records)
            {
                if(entity.EntityType==entityType && entity.PKValue()==key)
                    return entity;
            }
            return null;
        }
        #endregion

        public Dictionary<EntityType, Dictionary<string,EntityBase>> GetEntities()
        {
            Dictionary<EntityType, Dictionary<string, EntityBase>> entities =
                new Dictionary<EntityType, Dictionary<string, EntityBase>>();
            foreach(EntityBase entity in this.Records)
            {
                if(!entities.ContainsKey(entity.EntityType))
                {
                    Dictionary<string,EntityBase> entityBases=new Dictionary<string, EntityBase>();
                    entityBases.Add(entity.PKValue(), entity);
                    entities.Add(entity.EntityType, entityBases);
                }
                else
                {
                    Dictionary<string, EntityBase> entityBases = entities[entity.EntityType];
                    entityBases.Add(entity.PKValue(), entity);
                    entities[entity.EntityType] = entityBases;
                }
            }
            return entities;
        }

        public static Dictionary<EntityType, Dictionary<string,EntityBase>> GetEntities(List<EntityBase> entityList)
        {
            Dictionary<EntityType, Dictionary<string, EntityBase>> entities =
                new Dictionary<EntityType, Dictionary<string, EntityBase>>();
            foreach (EntityBase entity in entityList)
            {
                if (!entities.ContainsKey(entity.EntityType))
                {
                    Dictionary<string, EntityBase> entityBases = new Dictionary<string, EntityBase>();
                    entityBases.Add(entity.PKValue(), entity);
                    entities.Add(entity.EntityType, entityBases);
                }
                else
                {
                    Dictionary<string, EntityBase> entityBases = entities[entity.EntityType];
                    entityBases.Add(entity.PKValue(), entity);
                    entities[entity.EntityType] = entityBases;
                }
            }
            return entities;
        }

        public static List<Link> GetLinksConnectedToEntities(List<Link> allLinks, List<EntityBase> entityList)
        {
            Dictionary<EntityType, Dictionary<string, EntityBase>> entities = Network.GetEntities(entityList);
            List<Link> passingLinks=new List<Link>();
            foreach(Link link in allLinks)
            {
                EntityType fromType = EntityTypeUtil.GetEntityType(link.FromType);
                if(entities.ContainsKey(fromType) && 
                    entities[fromType].ContainsKey(link.FromKey))
                    passingLinks.Add(link);
                else if(link.FromType != link.ToType)
                {
                    EntityType toType = EntityTypeUtil.GetEntityType(link.ToType);
                    if(entities.ContainsKey(toType) && 
                        entities[toType].ContainsKey(link.ToKey))
                        passingLinks.Add(link);
                }
            }
            return passingLinks;
        }

        public static List<Link> GetLinksWithinEntities(List<Link> allLinks, List<EntityBase> entityList)
        {
            Dictionary<EntityType, Dictionary<string, EntityBase>> entities = 
                Network.GetEntities(entityList);
            List<Link> includedLinks = new List<Link>();
            foreach (Link link in allLinks)
            {
                EntityType fromType = EntityTypeUtil.GetEntityType(link.FromType);
                EntityType toType = EntityTypeUtil.GetEntityType(link.ToType);
                if (entities.ContainsKey(fromType) &&
                    entities[fromType].ContainsKey(link.FromKey))
                {
                    if (entities.ContainsKey(toType) &&
                        entities[toType].ContainsKey(link.ToKey))
                    {
                        includedLinks.Add(link);
                    }
                }
            }
            return includedLinks;
        }

        public Dictionary<int,List<EntityBase>> GroupConnectedEntities()
        {
            Dictionary<EntityBase, int> connectedComponents = new Dictionary<EntityBase, int>();
            Dictionary<EntityType, Dictionary<string, EntityBase>> entities = this.GetEntities();
            int groupID = 0;
            foreach (Link link in this.Links)
            {
                int existingGroupID = 0;
                EntityType fromType = EntityTypeUtil.GetEntityType(link.FromType);
                EntityBase fromEntity = entities[fromType][link.FromKey];
                EntityType toType = EntityTypeUtil.GetEntityType(link.ToType);
                EntityBase toEntity = entities[toType][link.ToKey];
                if (connectedComponents.ContainsKey(fromEntity))
                    existingGroupID = connectedComponents[fromEntity];
                if (connectedComponents.ContainsKey(toEntity))
                    existingGroupID = connectedComponents[toEntity];

                if (existingGroupID > 0)
                {
                    if (!connectedComponents.ContainsKey(fromEntity))
                        connectedComponents.Add(fromEntity, existingGroupID);
                    if (!connectedComponents.ContainsKey(toEntity))
                        connectedComponents.Add(toEntity, existingGroupID);
                }
                else
                {
                    groupID++;
                    connectedComponents.Add(fromEntity, groupID);
                    connectedComponents.Add(toEntity, groupID);
                }
            }
            foreach(EntityBase entity in this.Records)
            {
                if(!connectedComponents.ContainsKey(entity))
                    connectedComponents.Add(entity, ++groupID);
            }

            Dictionary<int, List<EntityBase>> connectedEntities = new Dictionary<int, List<EntityBase>>();
            foreach (EntityBase entity in connectedComponents.Keys)
            {
                int gID = connectedComponents[entity];
                if (connectedEntities.ContainsKey(gID))
                {
                    List<EntityBase> entities1 = connectedEntities[gID];
                    entities1.Add(entity);
                    connectedEntities[gID] = entities1;
                }
                else
                {
                    List<EntityBase> entities1 = new List<EntityBase>();
                    entities1.Add(entity);
                    connectedEntities.Add(gID, entities1);
                }
            }

            return connectedEntities;
        }

        public bool ContainsLink(Link link)
        {
            if (this.Links != null && this.Links.Count > 0)
            {
                foreach (Link link2 in this.Links)
                {
                    if (link.Directional)
                    {
                        if (link2.FromType == link.FromType && link2.FromKey == link.FromKey &&
                            link2.ToType == link.ToType && link2.ToKey == link.ToKey)
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (link2.FromType == link.FromType && link2.FromKey == link.FromKey &&
                            link2.ToType == link.ToType && link2.ToKey == link.ToKey)
                        {
                            return true;
                        }
                        else if (link2.ToType == link.FromType && link2.ToKey == link.FromKey &&
                            link2.FromType == link.ToType && link2.FromKey == link.ToKey)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public DataTable GetLinksAsTable()
        {
            DataTable dtLinks=new DataTable();
            dtLinks.Columns.Add("FromType", typeof (string));
            dtLinks.Columns.Add("ToType", typeof(string));
            dtLinks.Columns.Add("From", typeof(string));
            dtLinks.Columns.Add("To", typeof(string));
            dtLinks.Columns.Add("Distance", typeof (double));
            dtLinks.Columns.Add("Aggregate", typeof (int));
            dtLinks.Columns.Add("Directional", typeof (bool));

            Dictionary<EntityType, Dictionary<string, EntityBase>> entities = this.GetEntities();
            if(this.Links !=null && this.Links.Count > 0)
            {
                foreach(Link link in this.Links)
                {
                    DataRow dr = dtLinks.NewRow();
                    EntityType fromType = EntityTypeUtil.GetEntityType(link.FromType);
                    dr["FromType"] = fromType.ToString();
                    EntityType toType = EntityTypeUtil.GetEntityType(link.ToType);
                    dr["ToType"] = toType.ToString();
                    dr["From"] = entities[fromType][link.FromKey].Name;
                    dr["To"] = entities[toType][link.ToKey].Name;
                    dr["Distance"] = Math.Round(link.Distance, 2);
                    dr["Aggregate"] = link.Aggregates;
                    dr["Directional"] = link.Directional;
                    dtLinks.Rows.Add(dr);
                }
            }

            return dtLinks;
        }
    }

    public class NetworkTest
    {
        private Network _Network;

        public NetworkTest()
        {
            List<EntityBase> entities=new List<EntityBase>();
            GrantDO A = new GrantDO();
            A.ProjectID = 1;
            A.GrantNumber = "A";
            entities.Add(A);
            GrantDO B = new GrantDO();
            B.ProjectID = 2;
            B.GrantNumber = "B";
            entities.Add(B);
            GrantDO D = new GrantDO();
            D.ProjectID = 4;
            D.GrantNumber = "D";
            entities.Add(D);
            GrantDO E = new GrantDO();
            E.ProjectID = 5;
            E.GrantNumber = "E";
            entities.Add(E);
            PublicationDO C=new PublicationDO();
            C.Title = "C";
            C.PMID = 3;
            entities.Add(C);
            PublicationDO F = new PublicationDO();
            F.Title = "F";
            F.PMID = 6;
            entities.Add(F);
            List<Link> links=new List<Link>();
            Link ac = new Link(typeof(GrantDO), typeof(PublicationDO), "1", "3", 1, 1, LinkType.Citation, true);
            links.Add(ac);
            Link bc = new Link(typeof(GrantDO), typeof(PublicationDO), "2", "3", 1, 1, LinkType.Citation, true);
            links.Add(bc);
            Link cd = new Link(typeof(PublicationDO), typeof(GrantDO), "3", "4", 1, 1, LinkType.Citation, true);
            links.Add(cd);
            Link ce = new Link(typeof(PublicationDO), typeof(GrantDO), "3", "5", 1, 1, LinkType.Citation, true);
            links.Add(ce);
            Link df = new Link(typeof(GrantDO), typeof(PublicationDO), "4", "6", 1, 1, LinkType.Citation, true);
            links.Add(df);
            Link ef = new Link(typeof(GrantDO), typeof(PublicationDO), "5", "6", 1, 1, LinkType.Citation, true);
            links.Add(ef);
            this._Network=new Network("Test", entities, links);
        }

        public void RemovePub()
        {
            StreamWriter writer = new StreamWriter("NetworkTester.txt");
            this.Print(writer, this._Network);
            
            writer.WriteLine("After remove publication");
            this._Network.HideVertices(EntityType.Publications);
            this.Print(writer, this._Network);
            this._Network.ShowAllHiddenVertices();
            writer.WriteLine("After add back publication");
            this.Print(writer, this._Network);
            writer.Flush();
            writer.Close();
        }

        private void Print(StreamWriter writer, Network network)
        {
            foreach (Link link in network.Links)
            {
                writer.WriteLine("{0}->{1}", link.FromKey, link.ToKey);
            }
        }
    }
}
